﻿using System.Linq;

using Buddy.BehaviorTree;
using Buddy.Common;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Objects;

using WingIt;
using WingIt.Dynamics;
using WingIt.Routines.Mirrors;

namespace WingIt.Routines
{
    //Neo93
    [RevisionControlId("$Id: Corruption_Seer.cs 693 2012-08-13 17:05:06Z Chinajade $")]
    public class SorcererCorruption_SageSeer : MirrorRoutine
    {
        // MAINTAINERS NOTES:
        // * You will notice that lambda expression argument names are unique (e.g., "darkWardOn", "darkWardWhen", "joltWhen"),
        //   instead of generic (e.g., "ctx", "ret", "on", "doWhen", "castWhen").  PLEASE honor this convention!
        //   This allows us to quickly localize problems when looking at user's logs.  When the BehaviorTree encounters an exception
        //   (e.g., "object not found"), the location where an exception is thrown is identifiable only through the name
        //   of the lambda expression argument.  Such is the nature of BehaviorTrees.

        [Behavior(BehaviorType.Pull)]
        [Class(CharacterClass.Inquisitor, AdvancedClass.Sorcerer, SkillTreeId.SorcererCorruption)]
        [Class(CharacterClass.Consular, AdvancedClass.Sage, SkillTreeId.SageSeer)]
        public static Composite SorcererCorruption_SageSeer_Pull()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.BWcoreFixup_WaitForHarvestComplete(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                new Decorator(whenInParty => Me.IsInParty(), new Action(alwaysSucceed => RunStatus.Success)),
                new Decorator(whenNotInParty => !Me.IsInParty(), SorcererCorruption_SageSeer_Combat())
                );
        }

        [Behavior(BehaviorType.Combat)]
        [Class(CharacterClass.Inquisitor, AdvancedClass.Sorcerer, SkillTreeId.SorcererCorruption)]
        [Class(CharacterClass.Consular, AdvancedClass.Sage, SkillTreeId.SageSeer)]
        public static Composite SorcererCorruption_SageSeer_Combat()
        {
            // NB: This looks like a lot of movment, but 99% of the time, the MoveWithin and StopWithin will be passthroughs.
            // However, the extra care will keep the healer optimally positioned on the battlefield--no matter what the group
            // and mob spread.
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                // General
                Cast("Polarity Shift"),
                Cast("Unbreakable Will", unbreakableWillWhen => Me.IsStunned),
                Cast("Recklessness", recklessnessWhen => Tank.HealthPercent <= Global.Health.High),//Buff for 2 Mirrors
                Cast("Consumption", consumptionWhen => Me.HasMirrorBuff("Force Surge") && (Me.HealthPercent >= 90 || (Me.EnergyMax - Me.Energy) >= 50)),//Restores Force

                //Heal
                new Decorator(whenShieldNeeded => ShieldTarget != null,
                    new PrioritySelector(
                        CreateBTPS.MoveWithinRangeAndLoS(myShieldTarget => ShieldTarget, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myShieldTarget => ShieldTarget, Global.Distance.Ranged),
                        Cast("Static Barrier", staticBarrierOn => ShieldTarget, staticBarrierWhen => ShieldTarget != null)//Shield
                        )),
                new Decorator(resurgenceOnTankWhen => Me.HasMirrorAbility("Reconstruct") && !Tank.HasMirrorBuff("Reconstruct"),
                    new PrioritySelector(
                        CreateBTPS.MoveWithinRangeAndLoS(myTank => Tank, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myTank => Tank, Global.Distance.Ranged),
                        Cast("Resurgence", resurgenceOn => Tank) //HoT & Armorbuff
                        )),
                new Decorator(whenPartyHealNeeded => HealTarget != null,
                    new PrioritySelector(
                        DebugTools.CreateBTPS_InfoDump(ctx => string.Format("'{0}' needs heal, Health:{1}%, IsMoving:{2}", HealTarget.LoggableIdentifier(), HealTarget.HealthPercent, Me.IsMoving)),
                        CreateBTPS.MoveWithinRangeAndLoS(myHealTarget => HealTarget, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myHealTarget => HealTarget, Global.Distance.Ranged),
                        CastOnGround("Revivification", revivificationOn => Me.PartyPlayers().FirstOrDefault(p => p.HealthPercent <= Global.Health.High).Position, revivificationWhen => Me.PartyPlayers(p => p.HealthPercent <= Global.Health.Mid && p.IsInRange(1f)).Count() >= 3 && Me.HasMirrorBuff("Force Bending")),//AoE Heal
                        Cast("Dark Heal", darkHealOn => HealTarget, darkHealWhen => HealTarget.HealthPercent <= Global.Health.OhShit),//mid heal - low casttime
                        Cast("Dark Infusion", darkInfusionOn => HealTarget, darkInfusionWhen => HealTarget.HealthPercent <= Global.Health.Low),
                        Cast("Resurgence", resurgenceOn => HealTarget, resurgenceWhen => HealTarget.HealthPercent <= Global.Health.High && !HealTarget.HasMirrorBuff("Resurgence")),//Low Heal & HoT
                        Cast("Innervate", innervateOn => HealTarget, innervateWhen => HealTarget.HealthPercent <= Global.Health.Mid)//Low Heal & HoT
                        )),

                //Interrupt
                new Decorator(doInterruptWhen => InterruptTarget != null,
                    new PrioritySelector(
                        CreateBTPS.MoveWithinRangeAndLoS(myInterruptTarget => InterruptTarget, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myInterruptTarget => InterruptTarget, Global.Distance.Ranged),
                        Cast("Jolt", joltOn => InterruptTarget),
                        Cast("Electrocute", electrocuteOn => InterruptTarget)
                        )),

                //CC
                new Decorator(doCrowdControlWhen => CCTarget != null,
                    new PrioritySelector(
                        CreateBTPS.MoveWithinRangeAndLoS(myCrowdControlTarget => CCTarget, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myCrowdControlTarget => CCTarget, Global.Distance.Ranged),
                        Cast("Whirlwind", whirlwindOn => CCTarget),
                        Cast("Overload", overloadWhen => Me.MobCountAround(Global.Distance.MeleeAoE) >= 3)
                        )),

                //Dispell
                new Decorator(doDispellWhen => DispellTarget != null,
                    new PrioritySelector(
                        CreateBTPS.MoveWithinRangeAndLoS(myDispellTarget => DispellTarget, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myDispellTarget => DispellTarget, Global.Distance.Ranged),
                        Cast("Purge", purgeOn => DispellTarget, purgeWhen => DispellTarget != null)
                        )),

                // Damage Rotation
                new Decorator(whenOffensiveNeeded => MyTarget != null,
                    new PrioritySelector(
                        CreateBTPS.MoveWithinRangeAndLoS(myTarget => MyTarget, Global.Distance.Ranged),
                        CreateBTPS.StopWithinRangeAndLoS(myTarget => MyTarget, Global.Distance.Ranged),
                        Cast("Crushing Darkness"),
                        Cast("Shock"),
                        Cast("Force Lightning"),
                        Cast("Lightning Strike")
                        ))
            );
        }

        [Behavior(BehaviorType.OutOfCombat)]
        [Class(CharacterClass.Inquisitor, AdvancedClass.Sorcerer, SkillTreeId.SorcererCorruption)]
        [Class(CharacterClass.Consular, AdvancedClass.Sage, SkillTreeId.SageSeer)]
        public static Composite SorcererCorruption_SageSeer_OutOfCombat()
        {
            // NB: Apparently, BWcore will call this routine when in combat on occasion.  It is also called while we're pulling.
            return (new PrioritySelector(
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),
                new Decorator(oocBuffWhen => !Me.IsMounted,
                    new PrioritySelector(
                        BuffSelf("Force Speed", forceSpeedWhen => Me.IsMoving),
                        // Heal slacking party members, after battle...
                        // NB: We only need to do this when in a party, because our Rejuvenation will take care of the needs
                        // of self and companion.
                        new Decorator(whenPartyNeedsHeal => Me.IsInParty() && (HealTarget != null),
                            SorcererCorruption_SageSeer_Combat())
                        ))
                ));
        }
    }
}